namespace TripleA.Core.Pipeline
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using Interfaces;
    using Interfaces.Entities;

    public class DefaultPipeline<T> : IPipeline<T>
    {
        public IEnumerable<IPipelineStep<T>> Steps { get; set; }

        public DefaultPipeline(IPipelineConfig<T> config)
        {
            Steps = config.Steps;
        }

        public PipelineResult<T> Execute(T context)
        {
            var i = 0;
            var result = new PipelineResult<T>();           
            var timer = new Stopwatch();


            foreach (var step in Steps)
            {
                var stepResult = step.GenerateResult(i++);

                try
                {
                    timer.Restart();
                    
                    step.PreValidate(context);
                    step.Execute(context);
                    step.PostValidate(context);
                    stepResult.Succeeded();
                }
                catch (Exception ex)
                {
                    stepResult.Failed(context, ex);
                    break;
                }
                finally
                {
                    timer.Stop();
                    stepResult.Duration = timer.Elapsed;
                    result.StepResults.Add(stepResult);
                }
            }

            return result;
        }
    }
}